library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bus_arbiter is
	port(
	Address    : in std_logic_vector(15 downto 0);
	IOReq_n    : in std_logic;
	M1_n       : in std_logic;
	Read_n     : in std_logic;
	RAM_D      : in std_logic_vector(7 downto 0);
	UART_D     : in std_logic_vector(7 downto 0);
	IRQ_D      : in std_logic_vector(7 downto 0);
	IOPORT0_D  : in std_logic_vector(7 downto 0);
	IOPORT1_D  : in std_logic_vector(7 downto 0);
	ROM_D      : in std_logic_vector(7 downto 0);
	KEYB_D     : in std_logic_vector(7 downto 0);
	CONS_D     : in std_logic_vector(7 downto 0);
	DisableBootRom : in std_logic;
	Ram_CS     : out std_logic;
	Console_CS : out std_logic;
	Irq_CS     : out std_logic;
	Uart_CS    : out std_logic;
	IOPort0_CS : out std_logic;
	IOPort1_CS : out std_logic;
	Keyb_CS    : out std_logic;
	IntAck     : out std_logic;
	CPU_D      : out std_logic_vector(7 downto 0)
	);
end bus_arbiter;

architecture arbiter of bus_arbiter is
	signal sRom_CS     : std_logic := '0';
	signal sRamR_CS    : std_logic := '0';
	signal sRamW_CS    : std_logic := '0';
	signal sIrq_CS     : std_logic := '0';
	signal sUart_CS    : std_logic := '0';
	signal sKeyb_CS    : std_logic := '0';
	signal sIOPort0_CS : std_logic := '0';
	signal sIOPort1_CS : std_logic := '0';
	signal sConsole_CS : std_logic := '0';
begin
	sRom_CS     <= '1' when IOReq_n = '1' and                                     Address(15 downto 13) = "000" and DisableBootRom = '0' else '0'; -- addresses 0x0000-0x1FFF
	sRamR_CS    <= '1' when IOReq_n = '1' and Address(15 downto 13) /= "111" and (Address(15 downto 13) /= "000" or DisableBootRom = '1') else '0'; -- addresses 0x0000-0xDFFF or 0x2000-0xDFFF
	sRamW_CS    <= '1' when IOReq_n = '1' and Address(15 downto 13) /= "111" else '0'; -- addresses 0x0000-0xDFFF
	sIrq_CS     <= '1' when IOReq_n = '1' and Address(15 downto 11) = "11100" else '0';-- base address 0xE000
	sConsole_CS <= '1' when IOReq_n = '1' and Address(15 downto 12) = "1111" else '0';-- base address 0xF000
	sUart_CS    <= '1' when IOReq_n = '0' and M1_n = '1' and Address(7 downto 3) = "00000" else '0'; -- 0x0000 - 0x0008
	sKeyb_CS    <= '1' when IOReq_n = '0' and M1_n = '1' and Address(7 downto 3) = "00110" else '0'; -- 0x0030
	sIOPort0_CS <= '1' when IOReq_n = '0' and M1_n = '1' and Address(7 downto 3) = "00100" else '0'; -- 0x0020
	sIOPort1_CS <= '1' when IOReq_n = '0' and M1_n = '1' and Address(7 downto 3) = "00010" else '0'; -- 0x0010
	IntAck <= '1' when M1_n = '0' and IOReq_n = '0' else '0';
	
	CPU_D <=
		RAM_D     when sRamR_CS = '1' and Read_n = '0' else
		UART_D    when sUart_CS = '1' and Read_n = '0' else
		IRQ_D     when (sIrq_CS = '1' and Read_n = '0') or (M1_n = '0' and IOReq_n = '0') else
		KEYB_D    when sKeyb_CS = '1' and Read_n = '0' else
		IOPORT0_D when sIOPort0_CS = '1' and Read_n = '0' else
		IOPORT1_D when sIOPort1_CS = '1' and Read_n = '0' else
		ROM_D     when sRom_CS = '1' and Read_n = '0' else
		CONS_D    when sConsole_CS = '1' and Read_n = '0' else
		"00000000";

	Ram_CS <= sRamW_CS;
	Irq_CS <= sIrq_CS;
	Uart_CS <= sUart_CS;
	Keyb_CS <= sKeyb_CS;
	IOPort0_CS <= sIOPort0_CS;
	IOPort1_CS <= sIOPort1_CS;
	Console_CS <= sConsole_CS;
end arbiter;
